package com.teaclipse.model;

import java.util.ArrayList;/**
 * <p>Title: </p>
 *
 * <p>Description: </p>
 *
 * <p>Copyright: Copyright (c) 2006</p>
 *
 * <p>Company: </p>
 *
 * @author not attributable
 * @version 1.0
 */
public
class TeaInterpreter
{
    /**
     * points to the current quad in the quad list
     */
    protected int pointer = 0;

    /**
     * DeclarationSpace to store the variables created upon code generation
     */
    protected DeclarationSpace declarationSpace = new DeclarationSpace();

    /**
     * Stores the quad list
     */
    protected ArrayList currentQuadList = null;

    /**
     * constructor
     */
    public TeaInterpreter()
    {

    }

    /**
     * interpret the quads
     * @param quads ArrayList
     */
    public void interpret(ArrayList quads)
    {
        try
        {
            /* reset the variables before interpretting*/
            pointer = 0;
            declarationSpace = new DeclarationSpace();
            currentQuadList = quads;

            /* call the real interpret method*/
            realInterpret();

            /* output the declaration space */
            System.out.println("~~~results~~~~");
            System.out.println(declarationSpace);
        }
        catch(Exception ex)
        {
            System.out.println(ex.getMessage());
            ex.printStackTrace();
        }
    }

    /**
     * The realInterpret method - actually inteprets the quads
     * @throws InterpreterError
     * @throws Exception
     */
    protected void realInterpret() throws InterpreterError,Exception
    {
        System.out.println(declarationSpace);

        /* make sure the point hasn't gone outside the quad list*/
        while(pointer < currentQuadList.size())
        {
            boolean increment = true;
            Quad quad = (Quad) currentQuadList.get(pointer);

            if (quad == null) {
                throw new InterpreterError();
            }

            String operator = (String) quad.getOperator();

            /* decide what type of quad we are looking at and then
               execute that quad*/
            if (operator.equals(TeaQuadGeneratorConstants.DECLARE)) {
                declare(quad);
            } else if (operator.equals("ADD")) {
                add(quad);
            } else if (operator.equals("SUBTRACT")) {
                subtract(quad);
            } else if (operator.equals("MULT")) {
                multiply(quad);
            } else if (operator.equals("DIV")) {
                divide(quad);
            } else if (operator.equals("MOD")) {
                modulo(quad);
            } else if (operator.equals("NEGATE")) {
                negative(quad);
            } else if (operator.equals("POSITIVE")) {
                positive(quad);
            } else if (operator.equals("LESS_THAN")) {
                lessThan(quad);
            } else if (operator.equals("GREATER_THAN")) {
                greaterThan(quad);
            } else if (operator.equals("GREATER_THAN_EQUAL_TO")) {
                greaterThanEqualTo(quad);
            } else if (operator.equals("LESS_THAN_EQUAL_TO")) {
                lessThanEqualTo(quad);
            }

            else if (operator.equals("EQUAL_TO")) {
                equalTo(quad);
            } else if (operator.equals("NOT_EQUAL_TO")) {
                notEqualTo(quad);
            } else if (operator.equals("AND")) {
                and(quad);
            } else if (operator.equals("OR")) {
                or(quad);
            } else if (operator.equals("NOT")) {
                not(quad);
            }

            else if (operator.equals("ASSIGNMENT_STATEMENT")) {
                assign(quad);
            }

            else if (operator.equals(TeaQuadGeneratorConstants.BRANCHGTZ))
            {
                increment = false;
                branchGTZ(quad);
            } else if (operator.equals(TeaQuadGeneratorConstants.BRANCH)) {
                increment = false;
                branch(quad);
            } else if (operator.equals(TeaQuadGeneratorConstants.BRANCHLTEZ)) {
                increment = false;
                branchLTEZ(quad);
            }

            /* if we need to increment the point, do so*/
            if(increment)
            {
                pointer++;
            }
         }
    }

    /**
     * Execute the less than equal to quad
     * @param quad Quad
     */
    private void lessThanEqualTo(Quad quad) throws Exception
    {
        String lhs = (String) quad.getLeftHand();
        String rhs = (String) quad.getRightHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs) && checkValidity(rhs)) {
            int lhsValue = getValue(lhs);
            int rhsValue = getValue(rhs);

            int result = (lhsValue <= rhsValue) ? 1 : 0;

            declarationSpace.put(store, new Integer(result));
        }
    }

    /**
     * greaterThanEqualTo
     *
     * @param quad Quad
     */
    private void greaterThanEqualTo(Quad quad) throws Exception {
        String lhs = (String) quad.getLeftHand();
        String rhs = (String) quad.getRightHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs) && checkValidity(rhs)) {
            int lhsValue = getValue(lhs);
            int rhsValue = getValue(rhs);

            int result = (lhsValue >= rhsValue) ? 1 : 0;

            declarationSpace.put(store, new Integer(result));
        }
    }

    /**
     * equalTo
     *
     * @param quad Quad
     */
    private void equalTo(Quad quad) throws Exception {
        String lhs = (String) quad.getLeftHand();
        String rhs = (String) quad.getRightHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs) && checkValidity(rhs)) {
            int lhsValue = getValue(lhs);
            int rhsValue = getValue(rhs);

            int result = (lhsValue == rhsValue) ? 1 : 0;

            declarationSpace.put(store, new Integer(result));
        }
    }

    /**
     * notEqualTo
     *
     * @param quad Quad
     */
    private void notEqualTo(Quad quad) throws Exception
    {
       String lhs = (String) quad.getLeftHand();
       String rhs = (String) quad.getRightHand();
       String store = (String) quad.getRegister();

       if (checkValidity(lhs) && checkValidity(rhs)) {
           int lhsValue = getValue(lhs);
           int rhsValue = getValue(rhs);

           int result = (lhsValue != rhsValue)?1:0;

           declarationSpace.put(store, new Integer(result));
       }
    }

    /**
     * and
     *
     * @param quad Quad
     */
    private void and(Quad quad) throws Exception {
        String lhs = (String) quad.getLeftHand();
        String rhs = (String) quad.getRightHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs) && checkValidity(rhs)) {
            int lhsValue = getValue(lhs);
            int rhsValue = getValue(rhs);

            int result = (lhsValue == 1 && rhsValue == 1) ? 1 : 0;

            declarationSpace.put(store, new Integer(result));
        }
    }

    /**
     * or
     *
     * @param quad Quad
     */
    private void or(Quad quad) throws Exception
    {
        String lhs = (String) quad.getLeftHand();
        String rhs = (String) quad.getRightHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs) && checkValidity(rhs)) {
            int lhsValue = getValue(lhs);
            int rhsValue = getValue(rhs);

            int result = (lhsValue == 1 || rhsValue == 1)?1:0;

            declarationSpace.put(store, new Integer(result));
        }

    }

    /**
     * not
     *
     * @param quad Quad
     */
    private void not(Quad quad) throws Exception
    {
        String lhs = (String) quad.getLeftHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs))
        {
            int lhsValue = getValue(lhs);

            int result = (lhsValue == 1)?0:1;

            declarationSpace.put(store, new Integer(result));
        }

    }

    /**
     * greaterThan
     *
     * @param quad Quad
     */
    private void greaterThan(Quad quad) throws Exception
    {
        String lhs = (String) quad.getLeftHand();
        String rhs = (String) quad.getRightHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs) && checkValidity(rhs)) {
            int lhsValue = getValue(lhs);
            int rhsValue = getValue(rhs);

            int result = (lhsValue > rhsValue)?1:0;

            declarationSpace.put(store, new Integer(result));
        }

    }

    /**
     * lessThan
     *
     * @param quad Quad
     */
    private void lessThan(Quad quad) throws Exception
    {

        String lhs = (String) quad.getLeftHand();
        String rhs = (String) quad.getRightHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs) && checkValidity(rhs)) {
            int lhsValue = getValue(lhs);
            int rhsValue = getValue(rhs);

            int result = (lhsValue < rhsValue)?1:0;

            declarationSpace.put(store, new Integer(result));
        }
    }

    /**
     * Modulo
     * @param quad Quad
     * @throws Exception
     */
    private void modulo(Quad quad) throws Exception
    {
        String lhs = (String) quad.getLeftHand();
        String rhs = (String) quad.getRightHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs) && checkValidity(rhs)) {
            int lhsValue = getValue(lhs);
            int rhsValue = getValue(rhs);

            int result = lhsValue & rhsValue;

            declarationSpace.put(store, new Integer(result));
        }
    }

    /**
     * negate
     * @param quad Quad
     * @throws Exception
     */
    private void negative(Quad quad) throws Exception
    {
        String lhs = (String) quad.getLeftHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs)) {
            int lhsValue = getValue(lhs);

            int result = - lhsValue;

            declarationSpace.put(store, new Integer(result));
        }

    }

    /**
     * positive
     * @param quad Quad
     * @throws Exception
     */
    private void positive(Quad quad) throws Exception
    {
        String lhs = (String) quad.getLeftHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs)) {
            int lhsValue = getValue(lhs);

            int result = + lhsValue;

            declarationSpace.put(store, new Integer(result));
        }
    }

    /**
     * greater than zero
     * @param quad Quad
     * @throws Exception
     */
    private void branchGTZ(Quad quad) throws Exception
    {
        String lhs = (String)quad.getLeftHand();

        if(checkValidity(lhs))
        {
            int lhsValue = getValue(lhs);

            if(lhsValue > 0)
            {
                branch(quad);
            }
            else
            {
                pointer++;
            }

        }
    }

    /**
     * branch
     * @param quad Quad
     * @throws Exception
     */
    private void branch(Quad quad) throws Exception
    {
        int branchLocation = Integer.parseInt(quad.getRegister().toString());
        pointer = branchLocation;
      }

      /**
       * branch less than equal to zero
       * @param quad Quad
       * @throws Exception
       */
      private void branchLTEZ(Quad quad) throws Exception
    {
        String lhs = (String)quad.getLeftHand();

       if(checkValidity(lhs))
       {
           int lhsValue = getValue(lhs);

           if(lhsValue <= 0)
           {
               branch(quad);
           }
           else
           {
               pointer++;
           }
       }
    }

    /**
     * divide
     * @param quad Quad
     * @throws Exception
     */
    private void divide(Quad quad) throws Exception
    {
        String lhs = (String)quad.getLeftHand();
        String rhs = (String)quad.getRightHand();
        String store = (String)quad.getRegister();

       if(checkValidity(lhs) && checkValidity(rhs))
       {
          int lhsValue = getValue(lhs);
          int rhsValue = getValue(rhs);

          if(rhsValue == 0)
          {
              throw new Exception("Division by Zero: ");
          }

          int result = lhsValue/rhsValue;

          declarationSpace.put(store, new Integer(result));
       }
    }

    /**
     * gets the value from the string
     * @param value String
     * @return int
     */
    private int getValue(String value)
    {
        int returnValue = 0;
        try
        {
            /* try and cast the value to an integer..if this works then
               the value has to be an integer because an identifier cannot
                be an integer*/
            returnValue = new Integer(value).intValue();
        }
        catch(Exception ex)
        {
            /* if we get to this point, the value wasn't an integer so try
               to find its value in the declaration space*/
            returnValue = ((Integer)declarationSpace.get(value)).intValue();
        }

        return returnValue;
    }

    /**
     * checks the validity of the value  (if an integer or its a value
     * that is currently in the declaration space
     * @param value String
     * @return boolean
     * @throws Exception
     */
    private boolean checkValidity(String value) throws Exception
    {
        try
        {
            Integer tryToCast = new Integer(value);
            return true;
        }
        catch(Exception ex)
        {

            if (!declarationSpace.containsKey(value) &&
                    value.indexOf(TeaQuadGeneratorConstants.TEMP_CONSTANT) == -1) {
                throw new Exception("Undeclared Variable: " + value);
            }

            return true;
        }

        //return false;
    }

    /**
     * assign
     * @param quad Quad
     * @throws Exception
     */
    private void assign(Quad quad) throws Exception
    {
        String lhs = (String)quad.getLeftHand();
        String store = (String)quad.getRegister();

        if(checkValidity(lhs) && checkValidity(store))
        {
            int newValue = getValue(lhs);
            declarationSpace.put(store, new Integer(newValue));
        }
    }
    /**
     * multiply
     * @param quad Quad
     * @throws Exception
     */
    private void multiply(Quad quad) throws Exception
    {
        String lhs = (String) quad.getLeftHand();
        String rhs = (String) quad.getRightHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs) && checkValidity(rhs)) {
            int lhsValue = getValue(lhs);
            int rhsValue = getValue(rhs);

            int result = lhsValue * rhsValue;

            declarationSpace.put(store, new Integer(result));
        }
      }

      /**
       * subtract
       * @param quad Quad
       * @throws Exception
       */
      private void subtract(Quad quad) throws Exception {
        String lhs = (String) quad.getLeftHand();
        String rhs = (String) quad.getRightHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs) && checkValidity(rhs)) {
            int lhsValue = getValue(lhs);
            int rhsValue = getValue(rhs);

            int result = lhsValue - rhsValue;

            declarationSpace.put(store, new Integer(result));
        }

    }

    /**
     * add
     * @param quad Quad
     * @throws Exception
     */
    private void add(Quad quad) throws Exception {
        String lhs = (String) quad.getLeftHand();
        String rhs = (String) quad.getRightHand();
        String store = (String) quad.getRegister();

        if (checkValidity(lhs) && checkValidity(rhs)) {
            int lhsValue = getValue(lhs);
            int rhsValue = getValue(rhs);

            int result = lhsValue + rhsValue;

            declarationSpace.put(store, new Integer(result));
        }
    }

    /**
     * declare
     * @param quad Quad
     * @throws Exception
     */
    private void declare(Quad quad) throws Exception
    {
        String store = (String)quad.getRegister();

        if(declarationSpace.containsKey(store) &&
           store.indexOf(TeaQuadGeneratorConstants.TEMP_CONSTANT) == -1)
        {
            throw new Exception("Duplication Declaration: " + store);
        }

        declarationSpace.put(store, new Integer(0));
    }
}

